package rps.client.ui;

import static javax.swing.BoxLayout.Y_AXIS;
import static rps.game.data.FigureKind.FLAG;
import static rps.game.data.FigureKind.PAPER;
import static rps.game.data.FigureKind.ROCK;
import static rps.game.data.FigureKind.SCISSORS;
import static rps.game.data.FigureKind.TRAP;

import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.GraphicsEnvironment;
import java.awt.Point;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.rmi.RemoteException;
import java.util.Random;
import java.util.Vector;

import javax.swing.BoxLayout;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.JTextField;

import rps.game.Game;
import rps.game.data.Figure;
import rps.game.data.FigureKind;
import rps.game.data.Player;

public class GamePane {

	private final JPanel gamePane = new JPanel();
	private final JTextField chatInput = new JTextField();
	private final JTextArea chat = new JTextArea(4, 30);
	private final JScrollPane scrollPane = new JScrollPane(chat);

	private Game game;
	private Player player;
	public GameField gameField;
	public Controls controlField;
	private JFrame frame;
	
	private boolean alreadyAssigned = false;
	private boolean trapOrFlagMoved = false;
	private int flagPos, trapPos;
	//----------------------------- Assignment related fields -------------------------------
	private boolean assignmentInvoked = false;
	private FigureKind[] assignment = new FigureKind[42];
	private Vector<MyJButton> assignmentVector;
	private boolean firstAssignmentButtonPressed;
	private MyJButton firstPressedAssignmentButton;
	private MyJButton secondPressedAssignmentButton;
	//---------------------------------------------------------------------------------------
	
	
	//----------------------------- Images --------------------------------------------------
	private final String projPath = System.getProperty("user.dir");
	private final String background = "/src/rps/client/ui/images/background/";
	private final String opponent = "/src/rps/client/ui/images/opponent/";
	private final String own = "/src/rps/client/ui/images/own/";
	private final String arrow = "/src/rps/client/ui/images/arrow/";
	
	private final String flag = "flag/";
	private final String trap = "trap/";
	private final String scissors = "scissors/";
	private final String rock = "rock/";
	private final String paper = "paper/";
	private final String hidden = "hidden/";
	
	//own figures:
	public final  String ownNormalFlag = projPath + own + flag + "normal.png";
	public final  String ownSelectedFlag = projPath + own + flag + "selected.png";
	public final  String ownAssignFlag = projPath + own + flag + "assign.png";
	
	public final  String ownNormalRock = projPath + own + rock + "normal.png";
	public final  String ownSelectedRock = projPath + own + rock + "selected.png";
	public final  String ownNormalHiddenRock = projPath + own + rock + hidden + "normal.png";
	public final  String ownSelectedHiddenRock = projPath + own + rock + hidden + "selected.png"; 

	public final  String ownNormalTrap = projPath + own + trap + "normal.png";
	public final  String ownSelectedTrap = projPath + own + trap + "selected.png";
	public final  String ownAssignTrap = projPath + own + trap + "assign.png";

	public final  String ownNormalPaper = projPath + own + paper + "normal.png";
	public final  String ownSelectedPaper = projPath + own + paper + "selected.png";
	public final  String ownNormalHiddenPaper = projPath + own + paper + hidden + "normal.png";
	public final  String ownSelectedHiddenPaper = projPath + own + paper + hidden + "selected.png"; 

	public final  String ownNormalScissors = projPath + own + scissors + "normal.png";
	public final  String ownSelectedScissors = projPath + own + scissors + "selected.png";
	public final  String ownNormalHiddenScissors = projPath + own + scissors + hidden + "normal.png";
	public final  String ownSelectedHiddenScissors = projPath + own + scissors + hidden + "selected.png"; 
	
	//opponent figures:
	public final  String opponentNormalFlag = projPath + opponent + flag + "normal.png";
	
	public final  String opponentNormalRock = projPath + opponent + rock + "normal.png";
	public final  String opponentAttackRock = projPath + opponent + rock + "possibleAttack.png";

	public final  String opponentNormalTrap = projPath + opponent + trap + "normal.png";

	public final  String opponentNormalPaper = projPath + opponent + paper + "normal.png";
	public final  String opponentAttackPaper = projPath + opponent + paper + "possibleAttack.png";

	public final  String opponentNormalScissors = projPath + opponent + scissors + "normal.png";
	public final  String opponentAttackScissors = projPath + opponent + scissors + "possibleAttack.png";
	
	public final String opponentNormalHidden = projPath + opponent + hidden + "normal.png";
	public final String opponentAttackHidden = projPath + opponent + hidden + "possibleAttack.png";
	
	//background images:
	public final  String normalBackground = projPath  + background + "normal.png";
	public final  String moveBackground = projPath  + background + "move.png";
	
	//last move arrows:
	public final  String upMoveArrow = projPath + arrow + "up/move.png";
	public final  String upNormalArrow = projPath + arrow + "up/normal.png";
	public final  String downMoveArrow = projPath + arrow + "down/move.png";
	public final  String downNormalArrow = projPath + arrow + "down/normal.png";
	public final  String leftMoveArrow = projPath + arrow + "left/move.png";
	public final  String leftNormalArrow = projPath + arrow + "left/normal.png";
	public final  String rightMoveArrow = projPath + arrow + "right/move.png";
	public final  String rightNormalArrow = projPath + arrow + "right/normal.png";
	
	//---------------------------------------------------------------------------------------


	public GamePane(Container parent, JFrame frame) {

		gamePane.setLayout(new BoxLayout(gamePane, Y_AXIS));
		gameField = new GameField();
		this.frame = frame;
		
		gamePane.add(gameField);

		gamePane.add(scrollPane);
		gamePane.add(chatInput);
		
		
		controlField = new Controls();
		gamePane.add(controlField);
		
		MyJButton getAssignmentButton = new MyJButton("Get random Assignment!");
		getAssignmentButton.addActionListener(new AssignmentButtonActionListener());
		controlField.add(getAssignmentButton);

		chat.setLineWrap(true);
		chat.setEditable(false);

		gamePane.revalidate();
		gamePane.repaint();
		frame.pack();
		gamePane.setVisible(false);

		parent.add(gamePane);

		bindButtons();
	}
	
	
	/**
	 * Method converts given Figure Array into a corresponding GameField representation
	 * @param array - an Array of Figures
	 */
	
	public void buildGameField(Figure[] array) throws RemoteException{	
		gameField.clearButtonVector();
		gameField.removeAll();
		

		for(Figure f : array){
			
			if(f == null){
				MyJButton planeFieldButton = new MyJButton();
				planeFieldButton.setPlayer(null);
				planeFieldButton.setIcon(new ImageIcon(normalBackground));
				gameField.add2(planeFieldButton);
			continue;
			}
			
			
			FigureKind fig = f.getKind(); 
		
			
			if(fig == FigureKind.FLAG){
				MyJButton flagButton = new MyJButton();
				if(f.belongsTo(player)) {
					if (f.isDiscovered())
						flagButton.setIcon(new ImageIcon(ownNormalFlag));
					else
						flagButton.setIcon(new ImageIcon(ownNormalFlag));
					flagButton.setPlayer(player);
				}
				else {
					flagButton.setIcon(new ImageIcon(opponentNormalFlag));
					flagButton.setPlayer(game.getOpponent(player));
				}
				flagButton.setFigureKind(fig);
				gameField.add2(flagButton);	
				
			}
			else if(fig == FigureKind.HIDDEN){
				MyJButton hiddenButton = new MyJButton();
				hiddenButton.setPlayer(game.getOpponent(player));
				hiddenButton.setIcon(new ImageIcon(opponentNormalHidden));
				hiddenButton.setFigureKind(fig);
				gameField.add2(hiddenButton);
			}
			else if(fig == FigureKind.TRAP){
				MyJButton trapButton = new MyJButton();
				if(f.belongsTo(player)) {
					if (f.isDiscovered())
						trapButton.setIcon(new ImageIcon(ownNormalTrap));
					else
						trapButton.setIcon(new ImageIcon(ownNormalTrap));
					trapButton.setPlayer(player);
				}
				else {
					trapButton.setIcon(new ImageIcon(opponentNormalTrap));
					trapButton.setPlayer(game.getOpponent(player));
				}
				trapButton.setFigureKind(fig);
				gameField.add2(trapButton);
			}
			else if(fig == FigureKind.ROCK){
				MyJButton rockButton = new MyJButton();
				if(f.belongsTo(player)) {
					if (f.isDiscovered())
						rockButton.setIcon(new ImageIcon(ownNormalRock));
					else
						rockButton.setIcon(new ImageIcon(ownNormalHiddenRock));
					rockButton.setPlayer(player);
				}
				else {
					rockButton.setIcon(new ImageIcon(opponentNormalRock));
					rockButton.setPlayer(game.getOpponent(player));
				}
				rockButton.setFigureKind(fig);
				gameField.add2(rockButton);
			}
			else if(fig == FigureKind.PAPER){
				MyJButton paperButton = new MyJButton();
				if(f.belongsTo(player)) {
					if (f.isDiscovered())
						paperButton.setIcon(new ImageIcon(ownNormalPaper));
					else
						paperButton.setIcon(new ImageIcon(ownNormalHiddenPaper));
					paperButton.setPlayer(player);
				}
				else {
					paperButton.setIcon(new ImageIcon(opponentNormalPaper));
					paperButton.setPlayer(game.getOpponent(player));
				}
				paperButton.setFigureKind(fig);
				gameField.add2(paperButton);
			}
			else if(fig == FigureKind.SCISSORS){
				MyJButton scissorsButton = new MyJButton();
				if(f.belongsTo(player)) {
					if (f.isDiscovered())
						scissorsButton.setIcon(new ImageIcon(ownNormalScissors));
					else
						scissorsButton.setIcon(new ImageIcon(ownNormalHiddenScissors));
					scissorsButton.setPlayer(player);
				}
				else {
					scissorsButton.setIcon(new ImageIcon(opponentNormalScissors));
					scissorsButton.setPlayer(game.getOpponent(player));
				}
				scissorsButton.setFigureKind(fig);
				gameField.add2(scissorsButton);
			}
			
		}
//		gameField.get(game.getLastMove().getFrom())
		gameField.revalidate();
		gameField.repaint();
		
	}
	
	//-------------------- Assignments --------------------------------------------------
	/**
	 * Class implements ActionListener for "get random Assignment Button"
	 * @author Luke
	 *
	 */
	private class AssignmentButtonActionListener implements ActionListener{
		
		public void actionPerformed(ActionEvent event){
		
		assignmentVector = new Vector<>();
		assignment = getRandomAssignment();
		buildInitialAssignment();
		Point center = GraphicsEnvironment.getLocalGraphicsEnvironment().getCenterPoint();
		int width = frame.getSize().width;
		int height = frame.getSize().height;
		frame.setBounds(center.x - width / 2, center.y - height / 2, width, height);
			
		}	
	}
	
	
	/**
	 * Method creates random Assignment in form of a FigureKind Array
	 * @return random FigureKind Array
	 */ 
	public FigureKind[] getRandomAssignment(){
		
		FigureKind[] assign = new FigureKind[42];              
		int rock = 0;
		int scissors = 0;
		int paper = 0;
		int trap = 0;
		int fig = 4;
		int i = 0;
		Random r = new Random();
		if (!trapOrFlagMoved){
			i = r.nextInt(7);
			assign[i+35] = FLAG;
		}
		else{
			assign[trapPos] = TRAP;
			assign[flagPos] = FLAG;
			trap = 1;
		}
		System.out.println(trapPos+"  "+flagPos);
		for (int j=28; j<42; j++){
			r = new Random();
			if (rock == 4) fig = fig - 1;
			if (scissors == 4) fig = fig -1;
			if (paper == 4) fig = fig -1;
			if (trap == 1) fig = fig -1;
			if (fig == 0) return assign;
			else i = r.nextInt(fig);
			
			if (i == 0) {
				if (rock != 4){
					if (assign[j]== null){
						assign[j] = ROCK;
						rock = rock +1;
					}
				}
				else if (scissors != 4){
					if (assign[j]== null){
						assign[j] = SCISSORS;
						scissors = scissors +1;
					}
				}
				else if (paper != 4){
					if (assign[j]== null){
						assign[j] = PAPER;
						paper = paper +1;
					}
				}
				else if (trap != 1){
					if (assign[j]== null){
						assign[j] = TRAP;
						trap = trap +1;
					}
				}
				else return assign;
			}
			else if (i == 1){
				if (scissors != 4){
					if (assign[j]== null){
						assign[j] = SCISSORS;
						scissors = scissors +1;
					}
				}
				else if (paper != 4){
					if (assign[j]== null){
						assign[j] = PAPER;
						paper = paper +1;
					}
				}
				else if (trap != 1){
					if (assign[j]== null){
						assign[j] = TRAP;
						trap = trap +1;
					}
				}
				else if (rock != 4){
					if (assign[j]== null){
						assign[j] = ROCK;
						rock = rock +1;
					}
				}
				else return assign;
			}
			else if (i == 2){
				if (paper != 4){
					if (assign[j]== null){
						assign[j] = PAPER;
						paper = paper +1;
					}
				}
				else if (trap != 1){
					if (assign[j]== null){
						assign[j] = TRAP;
						trap = trap +1;
					}
				}
				else if (rock != 4){
					if (assign[j]== null){
						assign[j] = ROCK;
						rock = rock +1;
					}
				}
				else if (scissors != 4){
					if (assign[j]== null){
						assign[j] = SCISSORS;
						scissors = scissors +1;
					}
				}
				else return assign;
			}
			else {
				if (trap != 1){
					if (assign[j]== null){
						assign[j] = TRAP;
						trap = trap +1;
					}
				}
				else if (rock != 4){
					if (assign[j]== null){
						assign[j] = ROCK;
						rock = rock +1;
					}
				}
				else if (scissors != 4){
					if (assign[j]== null){
						assign[j] = SCISSORS;
						scissors = scissors +1;
					}
				}
				if (paper != 4){
					if (assign[j]== null){
						assign[j] = PAPER;
						paper = paper +1;
					}
				}
				else return assign;
			}
			fig = 4;
		}
		return assign;
		
	}

	
	
	/**
	 * Method takes initial Assignment in form of a FigureKind Array and build a Grid of corresponding JButtons
	 */
	private void buildInitialAssignment(){
		
		assignmentVector.clear();
		firstAssignmentButtonPressed = false;
		gameField.removeAll();
		
		for(FigureKind fig : assignment){
			
			if(fig == null){
				MyJButton planeField = new MyJButton();
				ImageIcon img = new ImageIcon(normalBackground);
				planeField.setIcon(img);
				gameField.add(planeField);
				assignmentVector.addElement(null);
			}
			if(fig == FigureKind.FLAG){
				MyJButton flagButton = new MyJButton();
				ImageIcon img = new ImageIcon(ownAssignFlag);
				flagButton.setIcon(img);
				flagButton.setFigureKind(FLAG);
				assignmentVector.addElement(flagButton);
				flagButton.addActionListener(new AssignmentFigureActionListener());
				gameField.add(flagButton);	
			}
			
			if(fig == FigureKind.TRAP){
				MyJButton trapButton = new MyJButton();
				ImageIcon img = new ImageIcon(ownAssignTrap);
				trapButton.setIcon(img);
				trapButton.setFigureKind(TRAP);
				assignmentVector.addElement(trapButton);
				trapButton.addActionListener(new AssignmentFigureActionListener());
				gameField.add(trapButton);
			}
			if(fig == FigureKind.ROCK){
				MyJButton rockButton = new MyJButton();
				ImageIcon img = new ImageIcon(ownNormalRock);
				rockButton.setIcon(img);
				rockButton.setFigureKind(ROCK);
				assignmentVector.addElement(rockButton);
				rockButton.addActionListener(new AssignmentFigureActionListener());
				gameField.add(rockButton);
			}
			if(fig == FigureKind.PAPER){
				MyJButton paperButton = new MyJButton();
				ImageIcon img = new ImageIcon(ownNormalPaper);
				paperButton.setIcon(img);
				paperButton.setFigureKind(PAPER);
				assignmentVector.addElement(paperButton);
				paperButton.addActionListener(new AssignmentFigureActionListener());
				gameField.add(paperButton);
			}
			if(fig == FigureKind.SCISSORS){
				MyJButton scissorsButton = new MyJButton();
				ImageIcon img = new ImageIcon(ownNormalScissors);
				scissorsButton.setIcon(img);
				scissorsButton.setFigureKind(SCISSORS);
				assignmentVector.addElement(scissorsButton);
				scissorsButton.addActionListener(new AssignmentFigureActionListener());
				gameField.add(scissorsButton);
			}
			
		}
		gameField.revalidate();
		gameField.repaint();
		frame.pack();
		
		
		
		if(!assignmentInvoked){
		
		MyJButton setAssignment = new MyJButton("set Assignment!");
		setAssignment.addActionListener(new ActionListener() {
			
			@Override
			public void actionPerformed(ActionEvent e) {
				alreadyAssigned = true;
				setAssignment();
				
				
			}
		});
		controlField.add(setAssignment);
		assignmentInvoked = true;
		
		}
		
	}
	
	/**
	 * Class implements ActionListener for JButtons of the Gamefield
	 * @author Luke
	 *
	 */
	public class AssignmentFigureActionListener implements ActionListener{
		
		
		@Override
		public void actionPerformed(ActionEvent e) {
			MyJButton source = (MyJButton) e.getSource();
			
			if(!firstAssignmentButtonPressed){
				firstPressedAssignmentButton = source;
				switchingFigure(firstPressedAssignmentButton);
				firstAssignmentButtonPressed = true;
			}
			
			else{
				secondPressedAssignmentButton = source;
				for(int i = 0; i < 42; i++){
					if(assignmentVector.get(i) == secondPressedAssignmentButton) {
						assignment[i] = firstPressedAssignmentButton.getFigureKind();
					}
				}
				for(int i = 0; i < 42; i++){
					if(assignmentVector.get(i) == firstPressedAssignmentButton) {
						assignment[i] = secondPressedAssignmentButton.getFigureKind();
					}
				}

				if(firstPressedAssignmentButton.getFigureKind() == TRAP || firstPressedAssignmentButton.getFigureKind() == FLAG || secondPressedAssignmentButton.getFigureKind() == TRAP || secondPressedAssignmentButton.getFigureKind() ==FLAG) {
					trapOrFlagMoved = true;
					flagPos = getFlagPosition();
					trapPos = getTrapPosition();
				}
				buildInitialAssignment();
				}
		}
	}
	
	
	private int getFlagPosition(){
		for(int i = 0; i < 42; i++){
			if(assignment[i] == FLAG) {
				return i;
			}
		}
		return 0;
		
	}
	
	private int getTrapPosition(){
		for(int i = 0; i < 42; i++){
			if(assignment[i] == TRAP) {
				return i;
			}
		}
		return 0;
		
	}
	
	/**
	 * changes the icon of the clicked button to indicate the switching figure
	 */
	private void switchingFigure(MyJButton button){
		switch (button.getFigureKind()) {
		case PAPER: 	button.setIcon(new ImageIcon(ownSelectedPaper));
			break;
		case ROCK: 		button.setIcon(new ImageIcon(ownSelectedRock));
			break;
		case SCISSORS:  button.setIcon(new ImageIcon(ownSelectedScissors));
			break;
		case FLAG: 	 	button.setIcon(new ImageIcon(ownSelectedFlag));
			break;
		case TRAP:  	button.setIcon(new ImageIcon(ownSelectedTrap));
			break;
		default: 		button.setIcon(button.getIcon());
			break;
		}
	}
	
	
	/**
	 * Method converts Gamefield representation into initial Assignment in form of a FigureKind Array and submits initial via move invoke
	 */
	private void setAssignment(){
		  
		  Component[] c = gameField.getComponents();
		  FigureKind[] assignment = new FigureKind[42];
		  for(int i = 28; i < 42 ; i++){
		   switch (((MyJButton) c[i]).getFigureKind()){
		   case FLAG: assignment[i] = FigureKind.FLAG;
		    break;
		   case PAPER: assignment[i] = FigureKind.PAPER;
		    break;
		   case ROCK: assignment[i] = FigureKind.ROCK;
		    break;
		   case SCISSORS: assignment[i] = FigureKind.SCISSORS;
		    break;
		   case TRAP: assignment[i] = FigureKind.TRAP;
		    break;
		   default:
		    break;
		   }
		  }
		  try {
		   controlField.removeAll();
		   game.setInitialAssignment(player, assignment);
		  } catch (RemoteException e) {
		   // TODO Auto-generated catch block
		   e.printStackTrace();
		  }
		 }
	
	
	//-------------------------------------------------------------------------------------------
	
	private void bindButtons() {
		chatInput.addKeyListener(new KeyListener() {
			@Override
			public void keyPressed(KeyEvent e) {
				boolean isEnter = e.getKeyCode() == KeyEvent.VK_ENTER;
				if (isEnter) {
					addToChat();
				}
			}

			@Override
			public void keyTyped(KeyEvent e) {
			}

			@Override
			public void keyReleased(KeyEvent e) {
			}
		});
	}

	private void addToChat() {
		String message = chatInput.getText().trim();
		if (message.length() > 0) {
			try {
				game.sendMessage(player, message);
				chatInput.setText("");
			} catch (RemoteException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	public void hide() {
		gamePane.setVisible(false);
	}

	public void startGame(Player player, Game game) {
		this.player = player;
		this.game = game;
		gameField.game = game;
		gameField.player = player;
		reset();
		gamePane.setVisible(true);
	}

	public void receivedMessage(Player sender, String message) {

		if (chat.getText().length() != 0) {
			chat.append("\n");
		}
		String formatted = sender.getNick() + ": " + message;
		chat.append(formatted);
		chat.setCaretPosition(chat.getDocument().getLength());
	}
	
	public void fightProtocol() throws RemoteException{
		FigureKind figAttacker = game.getLastMove().getOldField()[game.getLastMove().getFrom()].getKind();
		FigureKind figAttacked = game.getLastMove().getOldField()[game.getLastMove().getTo()].getKind();
		
		Player attackingPlayer;
		if (game.getLastMove().getOldField()[game.getLastMove().getFrom()].belongsTo(player))
			attackingPlayer = player;
		else
			attackingPlayer = game.getOpponent(player);
		
		Player attackedPlayer;
		if (attackingPlayer == player)
			attackedPlayer = game.getOpponent(player);
		else
			attackedPlayer = player;
		
		String formatted = figAttacker.toString() + " (" + attackingPlayer.getNick() + ") attacked " + figAttacked.toString() + " (" + attackedPlayer.getNick() + ")\n";
		chat.append(formatted);
		chat.setCaretPosition(chat.getDocument().getLength());
	}

	private void reset() {
		chat.setText(null);
	}
	
	
}